import population

class HallOfX(population.Population):
    def __init__(self, parent):
        population.Population.__init__(self)
        self.parent = parent

    def select(self):
        neighb = self.parent.neighbors
        parent = ([self] + neighb)[population.biasedChoice(len(neighb) + 1)]
        return parent

class HallOfFame(HallOfX):
    def __init__(self, parent):
        HallOfX.__init__(self, parent)

    def select(self):
        return HallOfX.select(self).hof.select()

class HallOfShame(HallOfX):
    def __init__(self, parent):
        HallOfX.__init__(self, parent)

    def select(self):
        return HallOfX.select(self).hos.select()



DEMOTE_FACTOR = 0.1
# format of adaption [modpop, position, value]

class Adaptable:
    def __init__(self, *args):
        self.neighbors = set()

        # TODO initialize HOF

    def select_adaption(self):
        return self.hof.select()

    def modify(self, adaption_index):
        adaption = self.hof[adaption_index]
        mod_pop = adaption[0]
        mod_pop.modify(self, adaption[1])

    def promote(self, adaption_index):
        self.hof.promote(adaption_index)

    def demote(self, adaption_index):
        mod_pop = self.hof[adaption_index][0]
        position = self.hof[adaption_index][1]
        mod_pop[position] *= DEMOTE_FACTOR
        del self.hof[adaption_index]
        self[index][-1]

        self.hof.append(self.produce_adaption())

    def produce_adaption(self):
        # TODO fancy adaption leeching from neighbors
        # TODO choose mod_pop to select from
        adaption = mod_pop.select()
        if adaption in self.hof:
            return self.produce_adaption()
        else:
            return adaption

    def neighbor_compare(self, n1, n2):
        return cmp(dot_product(self, n2), dot_product(self, n1))



class HallOfFame(list):
    def __new__(cls, *args):
        return list.__new__(cls)

    def __init__(self, contents = []):
        list.__init__(self)

        self.extend(contents)

    def select(self):
        return population.biasedChoice(len(self))

    def promote(self, index):
        self[index][0].promote()
        if index > 0:
            entry = self[index]
            self[index] = self[index - 1]
            self[index - 1] = entry


class RotationPop:
    def select(self):
        return
# cos a sin a
# -sin a cos a
